<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Nuxt TypeScript 配置与 Prisma 集成指南</title>
    <style>
         :root {
            --primary: #00DC82;
            --secondary: #18181B;
            --accent: #3B82F6;
            --light: #F4F4F5;
            --dark: #27272A;
            --text: #18181B;
            --text-light: #71717A;
            --border: #E4E4E7;
            --success: #10B981;
            --warning: #F59E0B;
            --error: #EF4444;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }
        
        body {
            background-color: var(--light);
            color: var(--text);
            line-height: 1.6;
            padding: 0;
            margin: 0;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 2rem;
        }
        
        header {
            background: linear-gradient(135deg, var(--secondary), var(--dark));
            color: white;
            padding: 2rem 0;
            margin-bottom: 2rem;
        }
        
        header h1 {
            font-size: 2.5rem;
            margin-bottom: 0.5rem;
        }
        
        header p {
            font-size: 1.2rem;
            color: rgba(255, 255, 255, 0.8);
            max-width: 800px;
        }
        
        .card {
            background: white;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
            padding: 1.5rem;
            margin-bottom: 2rem;
            border: 1px solid var(--border);
        }
        
        .card h2 {
            color: var(--primary);
            margin-bottom: 1rem;
            font-size: 1.5rem;
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }
        
        .card h3 {
            color: var(--dark);
            margin: 1.5rem 0 0.5rem;
            font-size: 1.2rem;
        }
        
        .code-block {
            background: var(--secondary);
            color: var(--light);
            border-radius: 8px;
            padding: 1.2rem;
            margin: 1rem 0;
            overflow-x: auto;
            font-family: 'Fira Code', monospace;
            font-size: 0.9rem;
            line-height: 1.5;
        }
        
        .code-comment {
            color: #6EE7B7;
            font-style: italic;
        }
        
        .code-keyword {
            color: #FF7CE5;
        }
        
        .code-string {
            color: #FFE066;
        }
        
        .code-function {
            color: #7DD3FC;
        }
        
        .code-number {
            color: #93C5FD;
        }
        
        .file-structure {
            background: var(--secondary);
            color: var(--light);
            border-radius: 8px;
            padding: 1.5rem;
            margin: 1rem 0;
            font-family: 'Fira Code', monospace;
        }
        
        .file-item {
            margin-left: 1.5rem;
            padding: 0.2rem 0;
        }
        
        .file-item::before {
            content: "📄 ";
        }
        
        .folder {
            margin-top: 0.5rem;
        }
        
        .folder-name {
            font-weight: bold;
            cursor: pointer;
            display: flex;
            align-items: center;
            gap: 0.3rem;
        }
        
        .folder-name::before {
            content: "📁 ";
        }
        
        .folder-content {
            margin-left: 1.5rem;
            display: none;
        }
        
        .folder.expanded .folder-content {
            display: block;
        }
        
        .step {
            display: flex;
            align-items: flex-start;
            gap: 1rem;
            margin-bottom: 1.5rem;
        }
        
        .step-number {
            background: var(--primary);
            color: white;
            width: 32px;
            height: 32px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
            font-weight: bold;
        }
        
        .step-content {
            flex: 1;
        }
        
        .tip {
            background: #ECFDF5;
            border-left: 4px solid var(--success);
            padding: 1rem;
            margin: 1rem 0;
            border-radius: 0 4px 4px 0;
        }
        
        .warning {
            background: #FFFBEB;
            border-left: 4px solid var(--warning);
            padding: 1rem;
            margin: 1rem 0;
            border-radius: 0 4px 4px 0;
        }
        
        .error {
            background: #FEF2F2;
            border-left: 4px solid var(--error);
            padding: 1rem;
            margin: 1rem 0;
            border-radius: 0 4px 4px 0;
        }
        
        .command {
            background: var(--dark);
            color: white;
            padding: 0.5rem 1rem;
            border-radius: 6px;
            font-family: 'Fira Code', monospace;
            display: inline-block;
            margin: 0.3rem 0;
        }
        
        @media (max-width: 768px) {
            .container {
                padding: 1rem;
            }
            header h1 {
                font-size: 2rem;
            }
            .code-block {
                font-size: 0.8rem;
                padding: 1rem;
            }
        }
    </style>
</head>

<body>
    <header>
        <div class="container">
            <h1>Nuxt TypeScript 配置与 Prisma 集成指南</h1>
            <p>解决 TypeScript 项目引用配置和 Prisma 种子脚本中的类型错误</p>
        </div>
    </header>

    <div class="container">
        <div class="card">
            <h2>📁 项目结构</h2>
            <p>正确的项目结构对于 TypeScript 配置至关重要。Nuxt 使用项目引用将代码分为不同的上下文。</p>

            <div class="file-structure">
                <div class="folder expanded">
                    <div class="folder-name">nuxt-project</div>
                    <div class="folder-content">
                        <div class="folder">
                            <div class="folder-name">.nuxt</div>
                            <div class="folder-content">
                                <div class="file-item">tsconfig.app.json</div>
                                <div class="file-item">tsconfig.server.json</div>
                                <div class="file-item">tsconfig.shared.json</div>
                                <div class="file-item">tsconfig.node.json</div>
                            </div>
                        </div>
                        <div class="folder">
                            <div class="folder-name">prisma</div>
                            <div class="folder-content">
                                <div class="file-item">schema.prisma</div>
                                <div class="file-item">seed.ts</div>
                                <div class="file-item">tsconfig.json</div>
                            </div>
                        </div>
                        <div class="folder">
                            <div class="folder-name">server</div>
                            <div class="folder-content">
                                <div class="file-item">api</div>
                                <div class="file-item">tsconfig.json</div>
                            </div>
                        </div>
                        <div class="file-item">tsconfig.json</div>
                        <div class="file-item">nuxt.config.ts</div>
                        <div class="file-item">package.json</div>
                    </div>
                </div>
            </div>
        </div>

        <div class="card">
            <h2>⚙️ TypeScript 配置</h2>
            <p>Nuxt 使用项目引用将 TypeScript 编译分为多个上下文，这需要特别注意配置。</p>

            <div class="step">
                <div class="step-number">1</div>
                <div class="step-content">
                    <h3>根目录 tsconfig.json</h3>
                    <div class="code-block">
                        <span class="code-comment">// ./tsconfig.json</span><br> {
                        <br> &nbsp;&nbsp;"files": [],<br> &nbsp;&nbsp;"references": [<br> &nbsp;&nbsp;&nbsp;&nbsp;{ "path": "./.nuxt/tsconfig.app.json" },<br> &nbsp;&nbsp;&nbsp;&nbsp;{ "path": "./.nuxt/tsconfig.server.json" },<br> &nbsp;&nbsp;&nbsp;&nbsp;{
                        "path": "./.nuxt/tsconfig.shared.json" },<br> &nbsp;&nbsp;&nbsp;&nbsp;{ "path": "./.nuxt/tsconfig.node.json" }<br> &nbsp;&nbsp;]
                        <br> }
                    </div>
                    <div class="tip">
                        这个配置使用项目引用将编译工作委托给子项目，每个子项目对应不同的编译上下文。
                    </div>
                </div>
            </div>

            <div class="step">
                <div class="step-number">2</div>
                <div class="step-content">
                    <h3>Prisma 目录配置</h3>
                    <div class="code-block">
                        <span class="code-comment">// ./prisma/tsconfig.json</span><br> {
                        <br> &nbsp;&nbsp;"extends": "../.nuxt/tsconfig.node.json",<br> &nbsp;&nbsp;"compilerOptions": {<br> &nbsp;&nbsp;&nbsp;&nbsp;"module": "CommonJS",<br> &nbsp;&nbsp;&nbsp;&nbsp;"moduleResolution": "node",<br> &nbsp;&nbsp;&nbsp;&nbsp;"esModuleInterop":
                        true<br> &nbsp;&nbsp;},
                        <br> &nbsp;&nbsp;"include": ["**/*.ts"],<br> &nbsp;&nbsp;"exclude": ["node_modules"]<br> }
                    </div>
                    <div class="tip">
                        为 Prisma 目录创建单独的 TypeScript 配置，确保种子脚本能够正确编译。
                    </div>
                </div>
            </div>
        </div>

        <div class="card">
            <h2>🌱 Prisma 种子脚本配置</h2>
            <p>正确配置 Prisma 种子脚本以解决类型错误和导入问题。</p>

            <div class="code-block">
                <span class="code-comment">// ./prisma/seed.ts</span><br>
                <span class="code-keyword">import</span> { PrismaClient } <span class="code-keyword">from</span> <span class="code-string">'@prisma/client'</span><br>
                <br>
                <span class="code-comment">// 直接在种子文件中实现 hashPassword</span><br>
                <span class="code-keyword">const</span> hashPassword = <span class="code-keyword">async</span> (password: <span class="code-keyword">string</span>): <span class="code-keyword">Promise</span>&lt;<span class="code-keyword">string</span>&gt;
                => {<br> &nbsp;&nbsp;
                <span class="code-keyword">const</span> bcrypt = <span class="code-keyword">await</span> <span class="code-function">import</span>(<span class="code-string">'bcryptjs'</span>)<br> &nbsp;&nbsp;
                <span class="code-keyword">return</span> bcrypt.<span class="code-function">hash</span>(password, <span class="code-number">12</span>)<br> }
                <br>
                <br>
                <span class="code-keyword">const</span> prisma = <span class="code-keyword">new</span> <span class="code-function">PrismaClient</span>()<br>
                <br>
                <span class="code-keyword">async</span> <span class="code-keyword">function</span> <span class="code-function">main</span>() {<br> &nbsp;&nbsp;console.
                <span class="code-function">log</span>(<span class="code-string">'开始种子数据...'</span>)<br> &nbsp;&nbsp;
                <br> &nbsp;&nbsp;
                <span class="code-keyword">const</span> hashedPassword = <span class="code-keyword">await</span> <span class="code-function">hashPassword</span>(<span class="code-string">'admin123'</span>)<br> &nbsp;&nbsp;
                <br> &nbsp;&nbsp;
                <span class="code-keyword">await</span> prisma.user.<span class="code-function">upsert</span>({<br> &nbsp;&nbsp;&nbsp;&nbsp;where: { username: <span class="code-string">'admin'</span> },<br> &nbsp;&nbsp;&nbsp;&nbsp;update: {},<br> &nbsp;&nbsp;&nbsp;&nbsp;create:
                {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;username: <span class="code-string">'admin'</span>,<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password: hashedPassword,<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email: <span class="code-string">'admin@example.com'</span><br>                &nbsp;&nbsp;&nbsp;&nbsp;}
                <br> &nbsp;&nbsp;})
                <br> &nbsp;&nbsp;
                <br> &nbsp;&nbsp;console.
                <span class="code-function">log</span>(<span class="code-string">'种子数据创建成功!'</span>)<br> }
                <br>
                <br>
                <span class="code-function">main</span>()<br> &nbsp;&nbsp;.
                <span class="code-function">catch</span>((e) => {<br> &nbsp;&nbsp;&nbsp;&nbsp;console.
                <span class="code-function">error</span>(<span class="code-string">'种子脚本执行错误:'</span>, e)<br> &nbsp;&nbsp;&nbsp;&nbsp;process.
                <span class="code-function">exit</span>(<span class="code-number">1</span>)<br> &nbsp;&nbsp;})
                <br> &nbsp;&nbsp;.
                <span class="code-function">finally</span>(<span class="code-keyword">async</span> () => {<br> &nbsp;&nbsp;&nbsp;&nbsp;
                <span class="code-keyword">await</span> prisma.$disconnect()<br> &nbsp;&nbsp;})
            </div>

            <div class="tip">
                使用绝对路径导入 PrismaClient，避免相对路径导致的模块解析问题。
            </div>
        </div>

        <div class="card">
            <h2>📦 Package.json 配置</h2>
            <p>更新 package.json 以确保正确的构建顺序和脚本执行。</p>

            <div class="code-block">
                <span class="code-comment">// ./package.json</span><br> {
                <br> &nbsp;&nbsp;"scripts": {<br> &nbsp;&nbsp;&nbsp;&nbsp;"build": "npx prisma generate && nuxt build",<br> &nbsp;&nbsp;&nbsp;&nbsp;"dev": "npx prisma generate && nuxt dev",<br> &nbsp;&nbsp;&nbsp;&nbsp;"generate": "npx prisma generate
                && nuxt generate",<br> &nbsp;&nbsp;&nbsp;&nbsp;"db:seed": "tsx --tsconfig prisma/tsconfig.json prisma/seed.ts",<br> &nbsp;&nbsp;&nbsp;&nbsp;"prisma:seed": "tsx --tsconfig prisma/tsconfig.json prisma/seed.ts"<br> &nbsp;&nbsp;},
                <br> &nbsp;&nbsp;"prisma": {<br> &nbsp;&nbsp;&nbsp;&nbsp;"seed": "tsx --tsconfig prisma/tsconfig.json prisma/seed.ts"<br> &nbsp;&nbsp;}
                <br> }
            </div>

            <div class="tip">
                确保在运行 Nuxt 构建命令之前先生成 Prisma 客户端，这样 TypeScript 可以正确解析类型。
            </div>
        </div>

        <div class="card">
            <h2>🚀 运行种子脚本</h2>
            <p>使用以下命令运行 Prisma 种子脚本：</p>

            <div class="command">npx prisma db seed</div>

            <p>或者直接运行：</p>

            <div class="command">npm run db:seed</div>

            <div class="warning">
                确保在运行种子脚本之前已经执行了 <code>npx prisma generate</code> 以生成 Prisma 客户端。
            </div>
        </div>

        <div class="card">
            <h2>✅ 总结</h2>
            <p>通过正确配置 TypeScript 项目引用和 Prisma 目录的单独配置，可以解决以下问题：</p>

            <ul style="margin-left: 1.5rem; margin-top: 0.5rem;">
                <li>TypeScript 模块解析错误</li>
                <li>PrismaClient 类型找不到的问题</li>
                <li>种子脚本中的导入路径问题</li>
                <li>构建顺序导致的类型错误</li>
            </ul>

            <div class="tip" style="margin-top: 1rem;">
                记住，Nuxt 的项目引用功能将 TypeScript 编译分为多个上下文，需要为每个上下文提供正确的配置。
            </div>
        </div>
    </div>

    <script>
        // 简单的文件夹展开/折叠功能
        document.querySelectorAll('.folder-name').forEach(folder => {
            folder.addEventListener('click', () => {
                folder.parentElement.classList.toggle('expanded');
            });
        });
    </script>
</body>

</html>